<template>
	<div class="calculator">
		<div class="display">{{ expression }}</div>
		<div class="buttons">
			<div v-for="button in buttons" :key="button" @click="handleButtonClick(button)" class="button">
				{{ button }}
			</div>
		</div>
	</div>
</template>

<script>
	// 定义状态常量
	const STATE_WAITING_FOR_NUMBER = 'waiting_for_number';
	const STATE_WAITING_FOR_OPERATOR = 'waiting_for_operator';
	const STATE_WAITING_FOR_RIGHT_PAREN = 'waiting_for_right_paren';

	export default {
		data() {
			return {
				expression: '',
				currentState: STATE_WAITING_FOR_NUMBER,
				openParenCount: 0,
				buttons: [
					'7', '8', '9', '/',
					'4', '5', '6', '*',
					'1', '2', '3', '-',
					'0', '.', '=', '+',
					'C', 'sin', 'cos', 'tan',
					'√', '^', '(', ')', '%',
					'log', 'ln', 'exp'
				]
			};
		},
		methods: {
			handleButtonClick(button) {
				if (button === 'C') {
					this.expression = '';
					this.currentState = STATE_WAITING_FOR_NUMBER;
					this.openParenCount = 0;
					return;
				}

				// 检查输入是否为非法字符
				if (!/[0-9+\-*/^().%a-zA-Z√]/.test(button)) {
					this.expression = 'Error: Invalid character';
					this.currentState = STATE_WAITING_FOR_NUMBER;
					this.openParenCount = 0;
					return;
				}

				// 处理无效的运算符组合
				if (/[+\-*/^%]/.test(button)) {
					const lastChar = this.expression.slice(-1);
					if (/[+\-*/^%]/.test(lastChar) && lastChar !== '-') {
						// 避免连续输入运算符（除了开头的负号）
						return;
					}
					if (this.expression === '' && button !== '-') {
						// 避免在表达式开头输入除负号以外的运算符
						return;
					}
				}

				if (this.currentState === STATE_WAITING_FOR_NUMBER) {
					if (this.expression === '0') {
						if (/[1-9]/.test(button)) {
							this.expression = button;
							this.currentState = STATE_WAITING_FOR_OPERATOR;
							return;
						} else if (button === '(') {
							this.expression = button;
							this.openParenCount++;
							this.currentState = STATE_WAITING_FOR_NUMBER;
							return;
						}
					}
					if (/[0-9(]/.test(button)) {
						if (button === '(') {
							this.openParenCount++;
						}
						this.expression += button;
						if (/\d/.test(button)) {
							this.currentState = STATE_WAITING_FOR_OPERATOR;
						}
					} else if (['sin', 'cos', 'tan', '√', 'log', 'ln', 'exp'].includes(button)) {
						if (this.expression === '0') {
							this.expression = '';
						}
						this.expression += button + '(';
						this.openParenCount++;
						this.currentState = STATE_WAITING_FOR_NUMBER;
					} else if (button === '-') {
						if (this.expression === '0') {
							this.expression = '-';
						} else {
							const lastChar = this.expression.slice(-1);
							if (/[+\-*/^%(]/.test(lastChar)) {
								this.expression += button;
							}
						}
					} else if (button === '.') {
						const lastNumber = this.getLastNumber(this.expression);
						if (lastNumber.length > 0 && !lastNumber.includes('.')) {
							this.expression += button;
							this.currentState = STATE_WAITING_FOR_NUMBER;
						}
					}
				} else if (this.currentState === STATE_WAITING_FOR_OPERATOR) {
					if (/\d/.test(button)) {
						this.expression += button;
						this.currentState = STATE_WAITING_FOR_OPERATOR;
					} else if (/[+\-*/^%)]/.test(button)) {
						if (button === ')') {
							if (this.openParenCount > 0) {
								this.expression += button;
								this.openParenCount--;
								if (this.openParenCount === 0) {
									this.currentState = STATE_WAITING_FOR_OPERATOR;
								} else {
									this.currentState = STATE_WAITING_FOR_RIGHT_PAREN;
								}
							} else {
								this.expression = 'Error: Mismatched parentheses';
								this.currentState = STATE_WAITING_FOR_NUMBER;
								this.openParenCount = 0;
								return;
							}
						} else if (button === '%') {
							const lastNumber = this.getLastNumber(this.expression);
							if (lastNumber) {
								const num = parseFloat(lastNumber);
								const newNum = num / 100;
								this.expression = this.expression.slice(0, -lastNumber.length) + newNum.toString();
							}
							this.currentState = STATE_WAITING_FOR_OPERATOR;
						} else {
							this.expression += button;
							this.currentState = STATE_WAITING_FOR_NUMBER;
						}
					}
				} else if (this.currentState === STATE_WAITING_FOR_RIGHT_PAREN) {
					if (button === ')') {
						if (this.openParenCount > 0) {
							this.expression += button;
							this.openParenCount--;
							if (this.openParenCount === 0) {
								this.currentState = STATE_WAITING_FOR_OPERATOR;
							}
						} else {
							this.expression = 'Error: Mismatched parentheses';
							this.currentState = STATE_WAITING_FOR_NUMBER;
							this.openParenCount = 0;
							return;
						}
					} else if (/[+\-*/^%]/.test(button)) {
						this.expression += button;
						this.currentState = STATE_WAITING_FOR_NUMBER;
					}
				}

				if (button === '=') {
					if (this.openParenCount === 0) {
						try {
							const result = this.evaluateExpression(this.expression);
							// 处理结果显示，避免科学计数法和过多小数位
							if (Number.isInteger(result)) {
								this.expression = result.toString();
							} else {
								this.expression = result.toFixed(8).replace(/\.?0+$/, '');
							}
							this.currentState = STATE_WAITING_FOR_NUMBER;
							this.openParenCount = 0;
						} catch (error) {
							this.expression = `Error: ${error.message}`;
							this.currentState = STATE_WAITING_FOR_NUMBER;
							this.openParenCount = 0;
						}
					} else {
						this.expression = 'Error: Mismatched parentheses';
						this.currentState = STATE_WAITING_FOR_NUMBER;
						this.openParenCount = 0;
					}
				}
			},
			evaluateExpression(expression) {
				// 处理连续运算符
				expression = this.handleConsecutiveOperators(expression);

				const precedence = {
					'+': 1,
					'-': 1,
					'*': 2,
					'/': 2,
					'^': 3,
					'%': 2
				};

				const applyOp = (operators, values) => {
					const op = operators.pop();
					const right = values.pop();
					let left = values.pop();
					switch (op) {
						case '+':
							values.push(left + right);
							break;
						case '-':
							values.push(left - right);
							break;
						case '*':
							values.push(left * right);
							break;
						case '/':
							if (right === 0) throw new Error('Division by zero');
							values.push(left / right);
							break;
						case '^':
							if (left === 0 && right < 0) throw new Error(
								'Invalid exponentiation: base 0 and negative exponent');
							values.push(Math.pow(left, right));
							break;
						case '%':
							values.push(left % right);
							break;
					}
				};

				const values = [];
				const operators = [];
				let i = 0;
				while (i < expression.length) {
					if (expression[i] === ' ') {
						i++;
						continue;
					}

					if (/[0-9.]/.test(expression[i]) || (expression[i] === '-' && (i === 0 || /[+\-*/(]/.test(expression[
							i - 1])))) {
						let numStr = '';
						if (expression[i] === '-') {
							numStr += '-';
							i++;
						}
						while (i < expression.length && (/[0-9.]/.test(expression[i]))) {
							numStr += expression[i++];
						}
						values.push(parseFloat(numStr));
						i--;
					} else if (expression[i] === '(') {
						operators.push(expression[i]);
					} else if (expression[i] === ')') {
						while (operators.length > 0 && operators[operators.length - 1] !== '(') {
							applyOp(operators, values);
						}
						if (operators.length === 0) throw new Error('Mismatched parentheses');
						operators.pop();
					} else if (/[+\-*/^%]/.test(expression[i])) {
						while (
							operators.length > 0 &&
							precedence[operators[operators.length - 1]] >= precedence[expression[i]]
						) {
							applyOp(operators, values);
						}
						operators.push(expression[i]);
					} else if (/[a-zA-Z√]/.test(expression[i])) {
						let func = '';
						while (i < expression.length && (/[a-zA-Z√]/.test(expression[i]))) {
							func += expression[i++];
						}
						i--;
						if (['sin', 'cos', 'tan', '√', 'log', 'ln', 'exp'].includes(func)) {
							if (i + 1 >= expression.length || expression[i + 1] !== '(') {
								throw new Error(`Incomplete function call: ${func}`);
							}
							let subExpr = '';
							let parenCount = 0;
							i++;
							while (i < expression.length) {
								if (expression[i] === '(') {
									parenCount++;
								} else if (expression[i] === ')') {
									parenCount--;
								}
								if (parenCount === 0) break;
								subExpr += expression[i++];
							}
							if (parenCount !== 0) throw new Error('Mismatched parentheses in function call');
							let result;
							let arg = this.evaluateExpression(subExpr);
							switch (func) {
								case 'sin':
									result = Math.sin(arg);
									break;
								case 'cos':
									result = Math.cos(arg);
									break;
								case 'tan':
									if (Math.cos(arg) === 0) throw new Error('Tangent is undefined at this angle');
									result = Math.tan(arg);
									break;
								case '√':
									if (arg < 0) throw new Error('Square root of negative number is undefined');
									result = Math.sqrt(arg);
									break;
								case 'log':
									if (arg <= 0) throw new Error('Logarithm of non - positive number is undefined');
									result = Math.log10(arg);
									break;
								case 'ln':
									if (arg <= 0) throw new Error(
										'Natural logarithm of non - positive number is undefined');
									result = Math.log(arg);
									break;
								case 'exp':
									result = Math.exp(arg);
									break;
							}
							values.push(result);
						} else {
							throw new Error(`Invalid function: ${func}`);
						}
					} else {
						throw new Error(`Invalid character: ${expression[i]}`);
					}
					i++;
				}

				while (operators.length > 0) {
					if (operators[operators.length - 1] === '(') throw new Error('Mismatched parentheses');
					applyOp(operators, values);
				}

				return values.pop();
			},
			handlePercentage(expression) {
				const lastNumber = this.getLastNumber(expression);
				const num = parseFloat(lastNumber);
				const newNum = num / 100;
				return expression.slice(0, -lastNumber.length) + newNum.toString();
			},
			handleConsecutiveOperators(expression) {
				let newExpression = '';
				for (let i = 0; i < expression.length; i++) {
					if (/[+\-*/^%]/.test(expression[i]) && /[+\-*/^%]/.test(expression[i + 1])) {
						if (expression[i] === '-' && expression[i + 1] === '-') {
							newExpression += '+';
							i++;
						} else {
							// 忽略连续的运算符
							continue;
						}
					} else {
						newExpression += expression[i];
					}
				}
				return newExpression;
			},
			getLastNumber(expression) {
				let i = expression.length - 1;
				let numStr = '';
				while (i >= 0 && (/[0-9.]/.test(expression[i]) || expression[i] === '-')) {
					numStr = expression[i] + numStr;
					i--;
				}
				return numStr;
			}
		}
	};
</script>
<style lang="scss" scoped>
	.calculator {
		width: 100%;
		max-width: 300px;
		margin: 20px auto;
		padding: 15px;
		background: #fff;
		border-radius: 8px;
		box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

		.display {
			height: 60px;
			background: #f8f8f8;
			border: 1px solid #ddd;
			border-radius: 4px;
			margin-bottom: 12px;
			padding: 8px;
			font-size: 28px;
			text-align: right;
			overflow-x: auto;
		}

		.buttons {
			display: grid;
			grid-template-columns: repeat(4, 1fr);
			gap: 8px;

			.button {
				background: #f0f0f0;
				border: 1px solid #ddd;
				border-radius: 4px;
				padding: 12px;
				font-size: 18px;
				color: #333;
				transition: all 0.2s ease;

				&:active {
					background: #e0e0e0;
					transform: scale(0.98);
				}

				&.operator {
					color: #007bff;
					font-weight: 500;
				}

				&.equal {
					background: #4CAF50;
					color: white;
					border-color: #4CAF50;
				}
			}
		}
	}
</style>